<?php
include_once ENTITIES."localidade.php";

include_once MODELS."localidade.php";

class LocalidadeController{
    
    private $modelLocalidade;
    
    public function __construct() {
        $this->modelLocalidade = new LocalidadeModel();
    }
    
    public function addLocalidade($localidade = null){
        if(is_null($localidade)) {
            $localidade = new Localidade();
            $this->linkLocalidade($localidade);
        }
        if(empty($localidade->nome) || empty($localidade->cidade)){
            $config->failInFunction("Os campos Nome e Cidade são necessários para inserção.");            
            $config->redirect("?op=cad-loca");
        }
        global $config;
        $res = false; $res_pos = false;
        $updateId = $config->filter("for-update-id");
        if(empty($updateId)) {
            if($this->adjustsLocalidadesPositionsInInsert($localidade)){
                $res = $this->modelLocalidade->insert($localidade);
            } else {
                $config->failInFunction("Não foi possível atualizar as posições das localidades na rota");
                $res_pos = true; 
            }
        } else {
            $localidade->id = $updateId;
            if($this->adjustsLocalidadesPositionsInUpdate($localidade)){
                $res = $this->modelLocalidade->update($localidade);
            } else {
                $config->failInFunction("Não foi possível atualizar as posições das localidades na rota");
                $res_pos = true;
            }
        }    
                
        if($res){
            $config->successInFunction();
        } else if(!$res_pos) {
            $config->failInFunction($this->modelLocalidade->handleError());
        } 
        
        $config->redirect("index.php?op=cad-loca");
    }
    
    private function linkLocalidade(Localidade &$localidade){
        global $config;
        $localidade->nome = mb_strtoupper($config->filter("nome"), 'UTF-8');
        $localidade->cidade = $config->filter("cidade");
        $localidade->rota = $config->filter("rota");
        $localidade->ordem = $config->filter("ordem");
    }
    
    public function removerLocalidade(){
        global $config;
        $localidade = $config->filter("loca");
        
        if(!$this->adjustsLocalidadesPositionsInDelete($this->getLocalidade($localidade))){
            $config->failInFunction("Falha ao atualizar posições das localidades");
        }
        
        $condition = LocalidadeModel::ID. " = ".$localidade;
        $res = $this->modelLocalidade->delete($condition);
        if($res){
            $config->successInFunction();
        } else {
            $config->failInFunction($this->modelLocalidade->handleError());
        }
        $config->redirect("index.php?op=cad-loca");
    }
    
    public function getLocalidade($localidade){
        $condition = LocalidadeModel::TABLE.".".LocalidadeModel::ID." = ".$localidade;
        $res = $this->modelLocalidade->select("*", $condition);
        if(count($res)){
            return $res[0];
        }
        return new Localidade();
    }
    
    public function getAllLocalidades($foreign_value = false, $byLoja = false){
        $condition = null;
        if($byLoja){
            $condition = RegiaoModel::LOJA." = $byLoja";
        }
        if($foreign_value){
            return $this->modelLocalidade->superSelect($condition);
        }
        $fields = array(self::NOME, self::CIDADE, self::ROTA, self::SEQ_ROTA, RegiaoModel::LOJA);
        return $this->modelLocalidade->select($fields, $condition);
    }

    public function getLocalidadesByCidade($id_cidade){
        $condition = LocalidadeModel::CIDADE." = $id_cidade";
        return $this->modelLocalidade->select("*", $condition);
    }
    
    public function getNumberOfPositionsByRota($rota){
        return count( $this->modelLocalidade->select(
                            LocalidadeModel::TABLE.".".LocalidadeModel::ID, 
                            LocalidadeModel::ROTA." = $rota") 
                    );
    }
    
    /* Adjusts positions in Rotas*/
    private function incrementOrdem(&$obj){ $obj->ordem++; }
    private function decrementOrdem(&$obj){ $obj->ordem--; }
    private function applyChangesOrdem($model, $objects, $ids, $field_id, $field_ordem){
        
        if(empty($objects)) return true;
        
        if(!method_exists($model, "simpleUpdate")) return false;
        if(is_array($ids)) $ids = implode (",", $ids);
        
        $condition = "$field_id IN ($ids)";
        
        if(!$model->simpleUpdate($field_ordem, "NULL" , $condition))
                return false;
        
        foreach ($objects as $obj){
            $condition = "$field_id = ".$obj->id; 
            if(!$model->simpleUpdate($field_ordem, $obj->ordem , $condition))
                return false;
        }
        return true;
    }
    
    private function adjustsLocalidadesPositionsInInsert(Localidade $new){
        $condition = LocalidadeModel::ROTA." = ".$new->rota." AND ".  LocalidadeModel::SEQ_ROTA." >= ".$new->ordem;
        $localidades = $this->modelLocalidade->select(array(LocalidadeModel::ID,
                                                            LocalidadeModel::SEQ_ROTA), $condition);
        $ids = array();
        foreach ($localidades as $localidade){
            $ids[] = $localidade->id;
            $localidade->ordem++;
        }
        return $this->applyChangesOrdem( $this->modelLocalidade, $localidades, $ids, 
                                         LocalidadeModel::ID, 
                                         LocalidadeModel::SEQ_ROTA );
        
    }
    
    private function adjustsLocalidadesPositionsInUpdate(Localidade $new){
        
        $old = $this->getLocalidade($new->id);
        
        if($new->rota != $old->rota) 
            return ( $this->adjustsLocalidadesPositionsInInsert($new) &&
                     $this->adjustsLocalidadesPositionsInDelete($old) );
        
        if($new->ordem == $old->ordem)
            return true;
        
        $condition = LocalidadeModel::ROTA." = ".$new->rota;
        if($new->ordem < $old->ordem){
            $condition .= " AND ".LocalidadeModel::SEQ_ROTA." < ".$old->ordem;
            $condition .= " AND ".LocalidadeModel::SEQ_ROTA." >= ".$new->ordem; 
            $fnc = "incrementOrdem";
        } else if($new->ordem > $old->ordem) {
            $condition .= " AND ".LocalidadeModel::SEQ_ROTA." > ".$old->ordem;
            $condition .= " AND ".LocalidadeModel::SEQ_ROTA." <= ".$new->ordem; 
            $fnc = "decrementOrdem";
        }
        
        $localidades = $this->modelLocalidade->select(array(LocalidadeModel::ID, 
                                                            LocalidadeModel::SEQ_ROTA), $condition);
        $ids = array();
        foreach ($localidades as $localidade){
            $ids[] = $localidade->id;
            $this->$fnc($localidade);
        }
        
        $this->modelLocalidade->simpleUpdate(LocalidadeModel::SEQ_ROTA, "NULL", 
                                             LocalidadeModel::ID." = ".$old->id);
        return $this->applyChangesOrdem( $this->modelLocalidade, $localidades, $ids, 
                                         LocalidadeModel::ID, LocalidadeModel::SEQ_ROTA );
        
    }
    
    private function adjustsLocalidadesPositionsInDelete(Localidade $old){
        $condition = LocalidadeModel::ROTA." = ".$old->rota." AND ".  LocalidadeModel::SEQ_ROTA." > ".$old->ordem;
        $localidades = $this->modelLocalidade->select(array(LocalidadeModel::ID, 
                                                            LocalidadeModel::SEQ_ROTA), $condition);
        $ids = array();
        foreach ($localidades as $localidade){
            $ids[] = $localidade->id;
            $localidade->ordem--;
        }
        $this->modelLocalidade->simpleUpdate(LocalidadeModel::SEQ_ROTA, "NULL", 
                                             LocalidadeModel::ID." = ".$old->id);
        return $this->applyChangesOrdem( $this->modelLocalidade, $localidades, $ids, 
                                         LocalidadeModel::ID, 
                                         LocalidadeModel::SEQ_ROTA );
    }

}
?>
